/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.ieslaferreria.creditsintesis.logicgame;

import com.jme.bounding.BoundingBox;
import com.jme.scene.Node;
import edu.ieslaferreria.creditsintesis.logicgame.actions.ConfigurationEvent;
import edu.ieslaferreria.creditsintesis.logicgame.actions.ProcessMobileObjectStateEvent;
import edu.ieslaferreria.creditsintesis.logicgame.actions.RmiEvent;
import edu.ieslaferreria.creditsintesis.logicgame.actions.Runner;
import edu.ieslaferreria.creditsintesis.logicgame.actions.SimpleRunner;
import edu.ieslaferreria.creditsintesis.logicgame.statemachineimpl.GenericStateMachine;
import edu.ieslaferreria.creditsintesis.rmi.GameEvent;
import java.util.HashMap;
import java.util.Map;


/**
 * Esta clase sirva para crear objetos con estado, tiene implementada una
 * maquina de estados y guarda una serie de atributos necesarios para
 * despues poder implemntarlos con RMI, es decir que guarda los atributos
 * necesarios de los objetos para poder volver a crearlos en cualquier momento
 * @author Ruben
 *
 */
public class ObjectWithStates extends Node{

    private final int AC_NO = SimpleRunner.AC_NOTHING;
    private final int AC_GF = SimpleRunner.AC_GO_FORWARD;
    private final int AC_GB = SimpleRunner.AC_GO_BACK;
    private final int AC_SR = SimpleRunner.AC_SPIN_RIGHT;
    private final int AC_SL = SimpleRunner.AC_SPIN_LEFT;
    private ActionStates actionStates;
    private String modelBoundName;
    private float scale;
    private HashMap<String, Parameter> parameters = new HashMap();
    private float offsetPosition = 0;
    private float height = 0;
    //private int actionToDo=-1;

    protected int[] stateToAction ={
      /*ST_STOPPED  ST_TO_FORWARD ST_TO_BACK ST_TO_RIGHT ST_TO_LEFT*/
        AC_NO,      AC_GF,        AC_GB,     AC_SR,      AC_SL    };

    private boolean requireUpdateAction = false;



    private Runner runner;

    protected StateMachine state;

    public ObjectWithStates(String name, StateMachine stateKind, ActionStates as){
      super(name);
      this.state = stateKind;
      this.actionStates = as;
    }

    public ObjectWithStates(StateMachine stateKind, ActionStates as){
      this.state = stateKind;
      this.actionStates = as;
    }

    public ObjectWithStates(String name, StateMachine stateKind, Runner runner, ActionStates as){
      super(name);
      this.state = stateKind;
      this.runner = runner;
      this.actionStates = as;
    }

    public ObjectWithStates(StateMachine stateKind, Runner runner, ActionStates as){
      this.state = stateKind;
      this.runner = runner;
      this.actionStates = as;
    }

    public ObjectWithStates(String name, ActionStates as) {
        this.actionStates=as;
        this.name=name;
        this.state = new GenericStateMachine(true);
    }

    public void processTransition(int pActivator){
        System.out.print("State of " + this.getName() + ": " + this.getState());
        this.state.setState(pActivator);
        System.out.println(" changes to " + this.getState());
        if(this.getActionToDo()>this.AC_NO){
            this.setRequireUpdateAction(true);
        }
    }

    public int getState(){
        return this.state.getState();
    }

    public void setRunner(Runner runner) {
        this.runner = runner;
    }

    /**
     * @return the runner
     */
    public Runner getRunner() {
        return runner;
    }

    public RmiEvent updateAction(float time){
        RmiEvent gm;
        this.setRequireUpdateAction(false);
        gm= runner.processAction(new ProcessMobileObjectStateEvent(this.getActionToDo(), this, time));
        return gm;

        //this.setRequireUpdateAction(false);
    }
    /**
     * @return the actionToDo
     */
    public int getActionToDo() {
        return stateToAction[this.getState()];
    }

    /**
     * @return the requireUpdateAction
     */
    public boolean isRequireUpdateAction() {
        return requireUpdateAction;
    }

    /**
     * @param requireUpdateAction the requireUpdateAction to set
     */
    public void setRequireUpdateAction(boolean requireUpdateAction) {
        System.out.println("Change require update: " + requireUpdateAction);
        if(requireUpdateAction && !this.requireUpdateAction){
            System.out.println("Object to validation queue");
            this.actionStates.getObjectsToValidateState().offer(this);
        }
        this.requireUpdateAction = requireUpdateAction;
    }

    public ConfigurationEvent getConfigurationEvent(){
        ConfigurationEvent confEvent=new ConfigurationEvent(this.name, this.getModelBoundName(),this.scale,null);
        confEvent.setParameters(parameters);
        return confEvent;
    }
    public void setMainsParameters(String modelBoundName, float scale){
        this.setModelBoundName(modelBoundName);
         if(this.modelBoundName.equals("BoundingBox")){
            this.height=((BoundingBox)this.getWorldBound()).yExtent;
        }
        this.scale=scale;
    }

    public void addParameter(String name,Parameter parameter){
        this.parameters.put(name, parameter);
    }
    public void addParameters(Map<String,Parameter> params){
        this.parameters.putAll(params);
    }
    public Map<String,Parameter> getParameters(){
        return this.parameters;
    }

    /**
     * @return the modelBoundName
     */
    public String getModelBoundName() {
        return modelBoundName;
    }

    /**
     * @param modelBoundName the modelBoundName to set
     */
    public void setModelBoundName(String modelBoundName) {
        this.modelBoundName = modelBoundName;
    }

    public float getOffsetPosition() {
/*        if (this.getWorldBound()instanceof BoundingBox){
            this.height= ((BoundingBox)this.getWorldBound()).yExtent;
        }
*/        return this.offsetPosition;
    }

    /**
     * @param height the height to set
     */
    public void setOffsetPosition(float height) {
            this.offsetPosition = height;
    }

    /**
     * @return the height
     */
    public float getHeight() {
       
        return height;
    }

    /**
     * @param height the height to set
     */
    public void setHeight(float height) {
        this.height = height;
    }
    
}





